<template>
  <div class="chat-container">
    <div class="chat-header">
      <div class="search-bar">
        <button class="icon-button">
          <img
            src="../assets/liandong.png"
            alt="logo"
            style="width: 40px; height: 40px"
          />
          <!-- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path d="M21 21L16.65 16.65M19 11C19 15.4183 15.4183 19 11 19C6.58172 19 3 15.4183 3 11C3 6.58172 6.58172 3 11 3C15.4183 3 19 6.58172 19 11Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
          </svg> -->
        </button>
        <span style="color: #2c2c36; font-size: 24px; font-weight: 600"
          >联东产业链智能体</span
        >
      </div>
      <div class="user-profile">
        <div class="profile-icon">
          <img
            src="https://tse3-mm.cn.bing.net/th/id/OIP-C.g5M-iZUiocFCi9YAzojtRAAAAA?w=219&h=219&c=7&r=0&o=5&pid=1.7"
            alt=""
            style="width: 50px; height: 50px; border-radius: 50%"
          />
        </div>
      </div>
      <!-- 添加测试按钮 -->
      <!-- <el-button @click="testMindMap" type="primary" style="margin-right: 20px;">测试思维导图</el-button> -->
    </div>

    <div
      class="messages-container"
      ref="messagesContainer"
      :class="{ 'messages-container-with-input': messages.length === 0 }"
    >
      <div class="welcome-message" v-if="showWelcomeMessage && isInitialLoad">
        <div class="welcome-content">
          <div class="welcome-header">
            <!-- <img src="../assets/robot-wave.gif" alt="AI Assistant" class="welcome-avatar"/> -->
            <h1>有什么可以帮忙的?</h1>
          </div>
          <div class="quick-actions">
            <div v-if="topConceptslist.length > 0" class="quick-action-row">
              <div
                class="quick-action-item"
                v-for="(concept, index) in topConceptslist.slice(0, 2)"
                :key="index"
                @click="quickAction(concept.concept_name)"
              >
              <svg t="1743496049676" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="909" width="50" height="50"><path d="M198.13511067 451.70511068c89.442 0 162.171 70.081 162.17100001 156.21299999s-72.73 156.215-162.17100001 156.21500001-162.171-70.081-162.171-156.21400001 72.728-156.214 162.17-156.214z m0 270.06399999c66.068 0 119.808-51.071 119.808-113.85s-53.74-113.85-119.80799999-113.85-119.80800001 51.07-119.80800001 113.85 53.74 113.85 119.808 113.85z m282.64-630.15c89.77399999 0 162.833 70.081 162.833 156.213s-73.06 156.213-162.833 156.213-162.832-70.08-162.83199999-156.213 73.06-156.213 162.83199999-156.213z m1e-8 270.064c66.441 0 120.47-51.071 120.46999999-113.84999999s-54.029-113.852-120.47-113.852-120.469 51.072-120.46899999 113.85099999 54.03 113.851 120.46999999 113.851z m282.63999999 90.02200001c89.443 0 162.172 70.081 162.17200001 156.213s-72.729 156.21400001-162.17100001 156.214-162.171-70.081-162.171-156.21400001 72.73000001-156.213 162.17-156.21299999z m0 270.06399999c66.07 0 119.809-51.071 119.809-113.84999999s-53.74-113.85-119.808-113.85000001-119.80800001 51.07-119.808 113.85000001 53.74 113.85 119.80800001 113.84999999z" fill="#1296db" p-id="910"></path><path d="M634.05211068 215.37811068c106.445 49.644 179.133 146.285 194.43999999 258.52199999l-41.95 5.71c-13.362-97.88200001-77.03-182.298-170.36199999-225.83999999l17.872-38.392z m-308.24900001 0.80699999l18.12 38.30900001c-83.65 39.591-143.39 111.927-163.86699999 198.452-2.44 10.425-4.344 21.078-5.585 31.918l-42.11500001-4.92300001c1.49-12.453 3.641-24.71899999 6.496-36.737 23.456-99.14399999 91.593-181.884 186.951-227.019zM705.54011068 719.10111068l30.2 29.74499999c-22.836 23.16699999-48.94 43.087-77.61000001 59.20100001-53.492 30.15899999-114.80199999 46.107-177.313 46.107-95.19199999 0-184.262-35.95100001-250.785-101.21200001l29.704-30.242c58.539 57.442 137.06 89.09000001 221.08200001 89.09 55.22999999 0 109.383-14.045 156.545-40.646 25.193-14.19 48.15400001-31.69 68.177-52.04299999z" fill="#1296db" p-id="911"></path></svg>
                <span>{{ concept.concept_name }}</span>
              </div>
            </div>
            <div v-if="topConceptslist.length > 2" class="quick-action-row">
              <div
                class="quick-action-item"
                v-for="(concept, index) in topConceptslist.slice(2, 4)"
                :key="index + 2"
                @click="quickAction(concept.concept_name)"
              >
              <svg t="1743496049676" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="909" width="50" height="50"><path d="M198.13511067 451.70511068c89.442 0 162.171 70.081 162.17100001 156.21299999s-72.73 156.215-162.17100001 156.21500001-162.171-70.081-162.171-156.21400001 72.728-156.214 162.17-156.214z m0 270.06399999c66.068 0 119.808-51.071 119.808-113.85s-53.74-113.85-119.80799999-113.85-119.80800001 51.07-119.80800001 113.85 53.74 113.85 119.808 113.85z m282.64-630.15c89.77399999 0 162.833 70.081 162.833 156.213s-73.06 156.213-162.833 156.213-162.832-70.08-162.83199999-156.213 73.06-156.213 162.83199999-156.213z m1e-8 270.064c66.441 0 120.47-51.071 120.46999999-113.84999999s-54.029-113.852-120.47-113.852-120.469 51.072-120.46899999 113.85099999 54.03 113.851 120.46999999 113.851z m282.63999999 90.02200001c89.443 0 162.172 70.081 162.17200001 156.213s-72.729 156.21400001-162.17100001 156.214-162.171-70.081-162.171-156.21400001 72.73000001-156.213 162.17-156.21299999z m0 270.06399999c66.07 0 119.809-51.071 119.809-113.84999999s-53.74-113.85-119.808-113.85000001-119.80800001 51.07-119.808 113.85000001 53.74 113.85 119.80800001 113.84999999z" fill="#1296db" p-id="910"></path><path d="M634.05211068 215.37811068c106.445 49.644 179.133 146.285 194.43999999 258.52199999l-41.95 5.71c-13.362-97.88200001-77.03-182.298-170.36199999-225.83999999l17.872-38.392z m-308.24900001 0.80699999l18.12 38.30900001c-83.65 39.591-143.39 111.927-163.86699999 198.452-2.44 10.425-4.344 21.078-5.585 31.918l-42.11500001-4.92300001c1.49-12.453 3.641-24.71899999 6.496-36.737 23.456-99.14399999 91.593-181.884 186.951-227.019zM705.54011068 719.10111068l30.2 29.74499999c-22.836 23.16699999-48.94 43.087-77.61000001 59.20100001-53.492 30.15899999-114.80199999 46.107-177.313 46.107-95.19199999 0-184.262-35.95100001-250.785-101.21200001l29.704-30.242c58.539 57.442 137.06 89.09000001 221.08200001 89.09 55.22999999 0 109.383-14.045 156.545-40.646 25.193-14.19 48.15400001-31.69 68.177-52.04299999z" fill="#1296db" p-id="911"></path></svg>
                <span>{{ concept.concept_name }}</span>
              </div>
            </div>
          </div>
          <div class="welcome-tips">
            <p>您也可以：</p>
            <ul>
              <li><i class="el-icon-search"></i> 搜索任意产业链信息</li>
              <li><i class="el-icon-data-analysis"></i> 查看产业链详细分析</li>
              <li><i class="el-icon-edit-outline"></i> 编辑和定制产业链图谱</li>
            </ul>
          </div>
        </div>
      </div>

      <div
        v-for="message in messages"
        :key="message.id"
        class="message"
        :class="message.role"
      >
        <div class="message-content">
          <div class="message-avatar">
            <i v-if="message.role === 'user'" class="el-icon-user"></i>
            <img
              v-else
              src="../assets/liandong.png"
              alt="AI"
              style="width: 24px; height: 24px"
            />
          </div>
          <div class="message-text">
            <div
              v-if="
                message.role === 'assistant' &&
                message.tasks &&
                message.tasks.length > 0
              "
            >
              <div
                v-for="(task, taskIndex) in message.tasks"
                :key="taskIndex"
                class="task-container"
                :class="{
                  collapsing: task.collapsing,
                  completed: task.completed,
                }"
              >
                <div class="task-header" @click="toggleTask(task)">
                  <h3
                    :class="[
                      'task-title',
                      { 'task-title-bold': task.title.includes('任务') },
                      task.customClass,
                    ]"
                  >
                    <span v-if="task.customClass">
                      <span style="color: black">本次任务总计耗时：</span>
                      <span style="color: #409eff">{{
                        task.title.match(/耗时：(.+?)，/)?.[1]
                      }}</span>
                      <span style="color: black">，共检索</span>
                      <span style="color: #409eff">{{
                        task.title.match(/检索(\d+)篇/)?.[1]
                      }}</span>
                      <span style="color: black">篇文章，生成节点数量：</span>
                      <span style="color: #409eff">{{
                        task.title.match(/数量：(\d+)个/)?.[1]
                      }}</span>
                      <span style="color: black">个</span>
                    </span>
                    <span v-else>{{ task.title }}</span>
                    <i
                      v-if="task.isCompleted"
                      class="el-icon-check task-complete-icon"
                    ></i>
                  </h3>
                  <i
                    :class="[
                      task.collapsed
                        ? 'el-icon-arrow-down'
                        : 'el-icon-arrow-up',
                      'task-toggle-icon',
                    ]"
                  ></i>
                </div>
                <ul class="task-steps" v-show="!task.collapsed">
                  <li
                    v-for="(step, stepIndex) in task.steps"
                    :key="stepIndex"
                    class="task-step"
                  >
                    <span
                      class="step-status"
                      v-if="step.type === '2' || step.type === '4'"
                    >
                      <i
                        v-if="
                          stepIndex === task.steps.length - 1 &&
                          task.isTypingStep
                        "
                        class="el-icon-loading"
                      ></i>
                      <i
                        v-else-if="
                          task.showStepChecks && task.completedSteps[stepIndex]
                        "
                        class="el-icon-check"
                      ></i>
                    </span>
                    <div class="step-content">
                      <template v-if="step.type === 'mindmap'">
                        <div class="mindmap-container">
                          <MindView :data="step.data" />
                        </div>
                      </template>
                      <template v-else-if="step.isLink">
                        <div class="article-link type5-content">
                          <a :href="step.url" target="_blank">{{
                            step.title
                          }}</a>
                        </div>
                      </template>
                      <template v-else>
                        <div
                          :class="{
                            'message-content-type': true,
                            'type2-content': step.type === '2',
                            'type4-content': step.type === '4',
                            // 'type5-content': step.type === '5'
                          }"
                        >
                          <typed-component
                            :text="step.content || ''"
                            :speed="typingSpeed"
                            :should-stop="!isTypingq"
                            @typing-complete="
                              onTaskStepComplete(task, stepIndex)
                            "
                          />
                        </div>
                      </template>
                    </div>
                  </li>
                  <!-- 只在当前活动任务中显示加载指示器 -->
                  <li
                    v-if="
                      (isProcessingMessage || pendingRequests.size > 0) &&
                      task.isActive &&
                      !task.isCompleted
                    "
                    class="task-step"
                  >
                    <div class="loading-indicator">
                      <div class="loading-dots">
                        <span></span>
                        <span></span>
                        <span></span>
                      </div>
                      <div class="loading-text">思考中...</div>
                    </div>
                  </li>
                </ul>
                <div
                  v-if="
                    task.title.includes('绘制') &&
                    task.steps.length >= 2 &&
                    task.steps[1].includes('已完成')
                  "
                  class="industry-chain-graph-container"
                >
                  <industry-chain-graph
                    :industryName_="currentIndustryName"
                  ></industry-chain-graph>
                </div>
              </div>
            </div>
            <p v-else>
              <typed-component
                v-if="message.role === 'assistant'"
                :text="message.fullContent || ''"
                :speed="1"
                :should-stop="!isTypingq"
                @typing-complete="onTypingComplete(message)"
              />
              <span v-else>{{ message.content }}</span>
            </p>
          </div>
        </div>
      </div>

      <!-- 添加底部加载状态指示器 -->
      <!-- <div v-if="isProcessingMessage || pendingRequests.size > 0" class="loading-indicator">
        <div class="loading-dots">
          <span></span>
          <span></span>
          <span></span>
        </div>
        <div class="loading-text">正在思考...</div>
      </div> -->
    </div>

    <!-- 添加确认弹框 -->
    <div v-if="showConfirmDialog" class="confirm-dialog">
      <div class="confirm-content">
        <div class="confirm-title" v-if="pendingsend"> 
          是否开始执行"{{ pendingSendMessage }}"产业链生成任务?
        </div>
        <div class="confirm-title" v-else></div>
        <div class="confirm-desc"></div>
        <div class="confirm-buttons">
          <el-button size="small" @click="cancelSend">取消</el-button>
          <el-button size="small" type="primary" @click="confirmSend"
            >确认</el-button
          >
        </div>
      </div>
    </div>

    <!-- 修改输入框容器的结构 -->
    <div class="input-wrapper">
      <div
        class="input-container"
        :class="{ 'input-container-bottom': messages.length > 0 }"
        @click="focusInput"
      >
        <div class="input-box" @click="focusInput">
          <input
            type="text"
            v-model="inputMessage"
            placeholder="请输入您想了解的产业链信息..."
            @keydown.enter="sendMessage"
            ref="inputField"
            :disabled="isTyping"
          />
        </div>
        <div class="button-container">
          <div class="left-buttons">
            <el-popover placement="top" width="300" trigger="hover">
              <div class="file-list-popover">
                <div v-if="successful_files.length === 0" class="no-files">
                  仅支持.doc\.docx、pdf、(PNG、JPG)，文件大小30MB以内
                </div>
                <div v-else class="file-list">
                  <div
                    v-for="(file, index) in successful_files"
                    :key="index"
                    class="file-item"
                  >
                    <div class="file-info">
                      <i class="el-icon-document"></i>
                      <span class="file-name">{{ file.name }}</span>
                    </div>
                    <div class="file-actions">
                      <el-button
                        type="text"
                        class="delete-btn"
                        @click="handleRemove(file, successful_files)"
                      >
                        <i class="el-icon-delete"></i>
                      </el-button>
                    </div>
                  </div>
                </div>
              </div>
              <el-upload
                slot="reference"
                class="upload-demo"
                ref="upload"
                :action="uploadUrl"
                :headers="uploadHeaders"
                :data="{
                  folder: 'general',
                }"
                name="files"
                :auto-upload="false"
                :http-request="customUpload"
                :on-preview="handlePreview"
                :on-remove="handleRemove"
                :before-upload="beforeUpload"
                :file-list="successful_files"
                :limit="5"
                :on-exceed="handleExceed"
                :on-change="handleFileChange"
                :show-file-list="false"
                multiple
              >
                <el-button
                  size="small"
                  type="primary"
                  plain
                  style="
                    width: 130.09px;
                    height: 100%;
                    padding: 12px 20px;
                    font-size: 14px;
                  "
                >
                  <i class="el-icon-paperclip"></i> 上传文件
                  <span v-if="successful_files.length > 0" class="file-count">
                    ({{ successful_files.length }})
                  </span>
                </el-button>
              </el-upload>
            </el-popover>
            <el-popover placement="bottom" trigger="hover" v-model="visible">
              <div>
                <div
                  v-for="(site, index) in searchSites"
                  :key="index"
                  class="search-site"
                >
                  <a :href="site.url" target="_blank">{{ site.name }}</a>
                  <div class="site-actions">
                    <el-button
                      type="text"
                      @click="editSite(index)"
                      class="action-button"
                    >
                      <i class="el-icon-edit-outline"></i>
                      <span class="action-text">编辑</span>
                    </el-button>
                    <el-button
                      type="text"
                      @click="deleteSite(index)"
                      class="action-button"
                    >
                      <i class="el-icon-delete"></i>
                      <span class="action-text">删除</span>
                    </el-button>
                  </div>
                </div>
                <el-button
                  type="primary"
                  size="small"
                  @click="showAddEditDialog"
                  style="width: 100%; margin-top: 10px"
                >
                  <i class="el-icon-plus"></i> 新增数据源
                </el-button>
              </div>
              <el-button
                slot="reference"
                @click="visible = !visible"
                type="primary"
                plain
              >
                <i class="el-icon-discover"></i> 搜索数据源({{
                  searchSites.length
                }})
              </el-button>
            </el-popover>
          </div>
          <el-button
            type="primary"
            circle
            class="send-button"
            @click="sendMessage"
            :disabled="isTyping"
            v-if="!isTypingq"
          >
            <i class="el-icon-s-promotion"></i>
          </el-button>
          <el-button
            type="info"
            circle
            class="send-button"
            @click="cancelProcess"
            v-else
          >
            <i class="el-icon-video-pause"></i>
          </el-button>
        </div>
      </div>
    </div>

    <!-- 添加/编辑对话框 -->
    <el-dialog
      :title="dialogTitle"
      :visible.sync="addEditDialogVisible"
      width="30%"
    >
      <el-form :model="siteForm" label-width="80px">
        <el-form-item label="网站名称">
          <el-input v-model="siteForm.name"></el-input>
        </el-form-item>
        <el-form-item label="网站URL">
          <el-input v-model="siteForm.url"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="addEditDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="confirmAddEditSite">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import IndustryChainGraph from "./IndustryChainGraph.vue";
import TypedComponent from "./TypedComponent.vue";
import MindView from "./MindView.vue";
import { fetchEventSource } from "@microsoft/fetch-event-source";
import api from "@/api";
let task1 = {};
let relatedContent = {};
export default {
  name: "ChatContainer",
  components: {
    IndustryChainGraph,
    TypedComponent,
    MindView,
  },
  props: {
    mindViewData: {
      type: Object,
      default: null,
    },
  },
  data() {
    return {
      inputMessage: "",
      lastInputMessage: "",
      visible: false,
      showWelcomeMessage: true,
      isInitialLoad: true,
      messages: [],
      messageQueue: [],
      isProcessingMessage: false,
      currentProcessingQuery: null,
      searchSites: [
        { name: "中商情报网", url: "askci.com" },
        { name: "前瞻", url: "qianzhan.com" },
        // { name: "知乎", url: "zhihu.com" },
      ],
      siteForm: {
        name: "",
        url: "",
      },
      editingIndex: -1,
      selectedSite: "https://www.google.com",
      addEditDialogVisible: false,
      isEditing: false,
      isTyping: false,
      isTypingq: false,
      typingSpeed:0,

      successful_files: [],
      currentIndustryName: "",
      currentCallback: null,
      processingMessage: false,
      currentType: null,
      messageBuffer: {},
      requestThrottleTime: 1000,
      lastRequestTime: 0,
      pendingRequests: new Set(),
      requestCache: new Map(),
      uploadHeaders: {
        Authorization: `${localStorage.getItem(
          "token_type"
        )} ${localStorage.getItem("access_token")}`,
      },
      uploadedCount: 0,
      totalUploadCount: 0,
      uploadedFiles: [],
      lastMessageTime: Date.now(),
      loadingCheckInterval: null,
      processedMessageIds: new Set(),
      topConceptslist: [],
      _mindViewDebounceTimer: null,
      _lastMindViewDataFingerprint: null,
      currentQuery: null,
      currentTask: {},
      articleUrlSet: new Set(),
      accumulatedArticles: [],
      localRelatedContent: null,
      lastArticle: null,
      collectedArticles: [], // 添加新属性用于存储所有文章
      qxmessage: "",
      showConfirmDialog: false,
      pendingSendMessage: "",
      _updateSidebarTimer: null,
      currentGroupId: null,
      globalArticleCount: 0, // 添加全局文章计数器
      extractedNodeTitle: "",
      taskProgress: 0, // 添加进度跟踪变量
      taskCount: 0,    // 添加任务计数器
      userIsScrolling: false, // 添加用户滚动状态跟踪
      lastScrollTop: 0, // 添加上次滚动位置
      scrollTimeoutId: null, // 添加滚动超时ID
      isWaitingForResponse: false,
      isReceiving: false,
      textToType: "",
      showSuggestions: false,
      pendingsend:false,
    };
  },
  computed: {
    dialogTitle() {
      return this.isEditing ? "编辑搜索网站" : "添加搜索网站";
    },
    uploadUrl() {
      return `${process.env.VUE_APP_API_SERVER}/api/files/upload-multiple`;
    },
  },
  watch: {
    messages: {
      handler(newMessages) {
        if (newMessages.length > 0 && this.showWelcomeMessage) {
          this.showWelcomeMessage = false;
        }
      },
      deep: true,
    },
    mindViewData: {
      handler(newData) {
        if (newData) {
          this.handleMindViewData(newData);
        }
      },
      immediate: true,
    },
    // 添加对taskProgress的监听
    taskProgress: {
      handler(newProgress) {
        // 构建进度信息对象
        const progressInfo = {
          progress: newProgress,
          taskName: this.currentQuery || '产业链分析',
          status: this.getProgressStatus(newProgress),
          totalArticles: this.globalArticleCount,
          timeElapsed: this.firstTaskStartTime ? Math.floor((Date.now() - this.firstTaskStartTime) / 1000) : 0
        };
        
        // 发送进度更新事件到Sidebar
        this.$root.$emit('update-progress', progressInfo);
      },
      immediate: true
    }
  },
  beforeRouteLeave(to, from, next) {
    // 路由切换时保存状态到sessionStorage
    sessionStorage.setItem(
      "chat_state",
      JSON.stringify({
        messages: this.messages,
        showWelcomeMessage: this.showWelcomeMessage,
        pendingRequests: Array.from(this.pendingRequests),
      })
    );
    next();
  },
  mounted() {
    // 添加任务步骤容器的滚动事件监听
    this.$nextTick(() => {
      const taskStepsContainers = document.querySelectorAll('.task-steps');
      taskStepsContainers.forEach(container => {
        if (container) {
          container.addEventListener('scroll', this.handleTaskStepsScroll);
        }
      });
    });
    
    // 原有的mounted代码
    api.user
      .topconcepts()
      .then((res) => {
        // console.log(res, '获取到的概念数据');
        if (res && res.data) {
          // 确保数据是数组形式
          this.topConceptslist = Array.isArray(res.data)
            ? res.data
            : Array.isArray(res.data.data)
            ? res.data.data
            : [];
          // console.log(this.topConceptslist, '处理后的概念数据');
        }
      })
      .catch((err) => {
        console.error("获取概念数据失败:", err);
        this.topConceptslist = [];
      });

    // 检查登录状态
    const accessToken = localStorage.getItem("access_token");
    const tokenType = localStorage.getItem("token_type");

    if (!accessToken || !tokenType) {
      localStorage.removeItem("isLoggedIn");
      this.$router.push("/login");
      return;
    }

    // 设置登录状态
    localStorage.setItem("isLoggedIn", "true");
    this.isInitialLoad = true;
  },
  beforeDestroy() {
    // 移除事件监听器
    const taskStepsContainers = document.querySelectorAll('.task-steps');
    taskStepsContainers.forEach(container => {
      if (container) {
        container.removeEventListener('scroll', this.handleTaskStepsScroll);
      }
    });
  },
  methods: {
    validateIndustryName(industryName) {
      return new Promise((resolve, reject) => {
        // 创建loading实例
        const loading = this.$loading({
          lock: true,
          text: "正在验证产业链名称...",
          spinner: "el-icon-loading",
          background: "rgba(255, 255, 255, 0.8)",
        });

        api.user
          .validateIndustryName({
            industry_name: industryName,
          })
          .then((res) => {
            // 关闭loading
            loading.close();

            if (res.status === "success") {
              // 验证成功，显示确认框
              this.showConfirmWithInfo(industryName, true);
              // 只有在验证成功时，才添加到侧边栏
              this.addNewChainToSidebar(industryName);
              resolve(true);
            } else {
              // 验证失败，显示错误提示
              this.showConfirmWithInfo(
                industryName,
                false,
                "请输入正确的产业链名称，如：汽车产业链"
              );
              resolve(false);
            }
          })
          .catch((err) => {
            // 关闭loading
            loading.close();

            console.error("验证产业链名称失败:", err);
            this.showConfirmWithInfo(industryName, false, "验证失败，请重试");
            resolve(false);
          });
      });
    },

    // 添加新方法，用于显示确认框
    showConfirmWithInfo(query, isValid, errorMessage = "") {
      // 获取已上传的文件名列表和数据源
      const uploadedFiles = this.successful_files.map((file) => file.name);
      const searchSources = this.searchSites.map((site) => site.name);

      this.pendingSendMessage = query;
      this.showConfirmDialog = true;

      this.$nextTick(() => {
        const descElement = document.querySelector(".confirm-desc");
        const confirmButton = document.querySelector(
          ".confirm-buttons .el-button--primary"
        );

        if (descElement) {
          let desc = "";

          if (!isValid) {
            this.pendingsend = false;
            // 验证失败时显示错误信息
            desc = `<div style="color: #F56C6C; margin-bottom: 10px;">输入的产业链名称不正确，请重新输入:如:汽车产业链...</div>`;
            if (confirmButton) {
              confirmButton.setAttribute("disabled", "disabled");
              confirmButton.style.opacity = "0.5";
              confirmButton.style.cursor = "not-allowed";
            }
          } else {
            this.pendingsend = true;
            // 验证成功时显示数据源和文件信息
            if (searchSources.length > 0) {
              desc += `<div style="color: #67C23A; margin-bottom: 8px;"><span style="display: inline-block; font-size: 20px; line-height: 20px; margin-right: 6px;">•</span>已确认"${searchSources.join(
                '""'
              )}"共${searchSources.length}个指定检索数据源</div>`;
            } else {
              desc += '<div style="color: #67C23A; margin-bottom: 8px;"><span style="display: inline-block; font-size: 20px; line-height: 20px; margin-right: 6px;">•</span>未配置检索数据源</div>';
            }

            if (uploadedFiles.length > 0) {
              desc += `<div style="color: #67C23A; margin-bottom: 8px;"><span style="display: inline-block; font-size: 20px; line-height: 20px; margin-right: 6px;">•</span>已确认上传"${uploadedFiles.join(
                '""'
              )}"共${uploadedFiles.length}个文件</div>`;
            } else {
              desc += '<div style="color: #67C23A; margin-bottom: 8px;"><span style="display: inline-block; font-size: 20px; line-height: 20px; margin-right: 6px;">•</span>用户未上传文件</div>';
            }

            desc +=
              '<div style="color: #67C23A; margin-top: 10px;"><span style="display: inline-block; font-size: 20px; line-height: 20px; margin-right: 6px;">•</span>产业链生成预计耗时30分钟，生成期间关闭网页<br><span style="display: inline-block; width: 20px;"></span>不影响生成过程和结果</div>';

            if (confirmButton) {
              confirmButton.removeAttribute("disabled");
              confirmButton.style.opacity = "1";
              confirmButton.style.cursor = "pointer";
            }
          }

          descElement.innerHTML = desc;
        }
      });
    },

    async processMessageQueue() {
      if (this.isProcessingMessage || this.messageQueue.length === 0) {
        return;
      }

      this.isProcessingMessage = true;
      const json = this.messageQueue.shift();

      try {
        await this.processMessage(json);
      } catch (error) {
        console.error("处理消息时出错:", error);
      } finally {
        this.isProcessingMessage = false;
        if (this.messageQueue.length > 0) {
          this.processMessageQueue();
        }
      }
    },

    async processMessage(json) {
      return new Promise(async (resolve) => {
        // 生成消息的唯一标识符
        const messageId = `${json.type}_${json.data}_${Date.now()}`;

        // 检查消息是否已经处理过
        if (this.processedMessageIds.has(messageId)) {
          resolve();
          return;
        }

        // 将消息ID添加到已处理集合中
        this.processedMessageIds.add(messageId);

        if (!relatedContent.articles) {
          relatedContent = {
            topic: {
              title: "产业链分析",
              type: "industry",
              articleCount: 0,
              analysisCount: 0,
            },
            articles: [],
          };
        }

        // 确保至少有一个 assistant 消息
        if (
          this.messages.length === 0 ||
          (this.messages.length === 1 && this.messages[0].role === "user")
        ) {
          this.messages.push({
            role: "assistant",
            content: "",
            isTyping: true,
            tasks: [],
          });
        }

        // 检查是否是 ping 消息
        if (json.data && json.data.startsWith("ping")) {
          resolve();
          return;
        }

        // 处理消息结束信号
        if (
          json.data &&
          (json.data.includes("处理结束") ||
            json.data.includes("分析结束") ||
            json.data.includes("总结完毕"))
        ) {
          this.processedMessageIds.clear();

          if (this.loadingCheckInterval) {
            clearInterval(this.loadingCheckInterval);
            this.loadingCheckInterval = null;
          }
          
          // 清除待处理请求并重置状态
          this.pendingRequests.delete(this.currentQuery);
          this.isWaitingForResponse = false;
          this.isTyping = false;
          this.isTypingq = false;
          
          resolve();
          return;
        }

        // 获取最后一条 assistant 消息
        const lastAssistantMessage = this.messages
          .filter((m) => m.role === "assistant")
          .pop();

        if (json.type === "1") {
          this.currentType = "1";
          // 更新任务计数和进度
          this.taskCount++;
          if (this.taskCount <= 4) {
            this.taskProgress = this.taskCount * 20;
            console.log(`当前任务进度: ${this.taskProgress}%`); // 打印进度
            
            // 向侧边栏发送任务进度更新事件
            this.$root.$emit('update-task-progress', {
              taskName: this.currentQuery || '产业链分析',
              progress: this.taskProgress
            });
          }
          
          // 只在第一次type1时记录开始时间
          if (!this.firstTaskStartTime) {
            this.firstTaskStartTime = Date.now();
          }

          // 处理上一个任务的完成状态
          if (task1.steps && task1.steps.length > 0) {
            if (task1.isTypingStep) {
              await new Promise((resolveWait) => {
                const checkTyping = setInterval(() => {
                  if (!task1.isTypingStep) {
                    clearInterval(checkTyping);
                    task1.showStepChecks = true;
                    task1.completed = true;
                    task1.isCompleted = true;
                    task1.isActive = false;
                    if (!task1.userCollapsed) {
                      task1.collapsed = true;
                    }
                    resolveWait();
                  }
                }, 10000);
              });
            } else {
              task1.showStepChecks = true;
              task1.completed = true;
              task1.isCompleted = true;
              task1.isActive = false;
              if (!task1.userCollapsed) {
                task1.collapsed = true;
              }
            }
          }

          // 将所有现有任务设置为非活动状态
          if (lastAssistantMessage && lastAssistantMessage.tasks) {
            lastAssistantMessage.tasks.forEach((t) => {
              t.isActive = false;
            });
          }

          // 创建新任务
          task1 = {
            title: json.data.replace(/(?<=搜索|提取|构建).*?(?=产业链)/, '"$&"'),
            steps: [],
            collapsed: false,
            currentStep: 0,
            stepContent: "",
            isTypingStep: false,
            totalSteps: 2,
            isCompleted: false,
            completed: false,
            isActive: true,
            completedSteps: {},
            showStepChecks: false,
            userCollapsed: false,
          };

          if (lastAssistantMessage && !lastAssistantMessage.tasks) {
            this.$set(lastAssistantMessage, "tasks", []);
          }

          if (lastAssistantMessage) {
            lastAssistantMessage.tasks.push(task1);
          }
          this.scrollToBottom();
          resolve();
        } else if (["2", "3", "4"].includes(json.type)) {
          // 直接使用实际的类型
          this.currentType = json.type;
          
          if (task1 && json.data) {
            try {
              let formattedData = json.data;
              
              // 根据不同type处理数据
              if (json.type === "2" && (json.data.includes("产业链信息") || json.data.includes("产业链总结"))) {
                  formattedData = json.data;  // 移除额外的换行符添加
              }
              else if (json.type === "3") {
                  formattedData = json.data
              }
              else if (json.type === "4") {
                  formattedData = json.data
              }

              if (json.data.startsWith("ping")) {
                  resolve();
                  return;
              }
              const titleMatch = json.data.match(
              /相关的\s*([^节点]*)节点/i
            );
            let extractedNodeTitle = null;
            if (titleMatch && titleMatch[1]) {
              extractedNodeTitle = titleMatch[1].trim();
              this.extractedNodeTitle = extractedNodeTitle;
            }

              // 等待上一个打字效果完成
              if (task1.isTypingStep) {
                await new Promise((resolveWait) => {
                  const checkTyping = setInterval(() => {
                    if (!task1.isTypingStep) {
                      clearInterval(checkTyping);
                      resolveWait();
                    }
                  }, 500);
                });
              }

              // 添加延迟确保内容显示
              await new Promise(resolve => setTimeout(resolve,1000));

              // 处理当前类型的数据
              await new Promise((resolveTyping) => {
                this.typeTaskStep(task1, formattedData, resolveTyping, json.type);
              });

              // 等待打字效果完成
              await new Promise((resolveWait) => {
                const checkTyping = setInterval(() => {
                  if (!task1.isTypingStep) {
                    clearInterval(checkTyping);
                    resolveWait();
                  }
                }, 500);
              });

            } catch (error) {
              console.error(`处理 type ${json.type} 数据时出错:`, error);
            }
          }
          if (json.type === "3") {
            let relations = [];
            let nodes = [];
            if (typeof json.data === "string") {
              // 处理返回的数据格式
              const lines = json.data.split("\n");
              lines.forEach((line) => {
                if (line.includes("relations:")) {
                  try {
                    // 提取 relations 后面的数组字符串
                    const relationsStr = line.split("relations:")[1].trim();
                    // 解析数组字符串
                    relations = JSON.parse(relationsStr);
                  } catch (e) {
                    console.error("解析relations数据失败:", e);
                  }
                }
              });
            }
            if (typeof json.data === "string") {
              // 处理返回的数据格式
              const lines = json.data.split("\n");
              lines.forEach((line) => {
                if (line.includes("nodes:")) {
                  try {
                    // 提取 nodes 后面的数组字符串
                    const relationsStr = line.split("nodes:")[1].trim();
                    // 解析数组字符串
                    nodes = JSON.parse(relationsStr);
                  } catch (e) {
                    console.error("解析nodes数据失败:", e);
                  }
                }
              });
            }
            if (relations && relations.length > 0) {
              // 设置最终进度为100%
              this.taskProgress = 100;
              console.log('思维导图生成完成，进度：100%');
              
              // 向侧边栏发送任务完成事件
              this.$root.$emit('update-task-progress', {
                taskName: this.currentQuery || '产业链分析',
                progress: 100
              });
              
              // 计算总耗时
              const elapsedTime = Date.now() - this.firstTaskStartTime;
              const minutes = Math.floor(elapsedTime / 60000);
              const seconds = ((elapsedTime % 60000) / 1000).toFixed(0);
              const timeString = `${minutes}分${seconds}秒`;

              // 数据指纹，用于去重
              const dataFingerprint = JSON.stringify({ relations, nodes });

              if (this._lastMindViewDataFingerprint === dataFingerprint) {
                resolve();
                return;
              }

              this._lastMindViewDataFingerprint = dataFingerprint;

              // 统计节点数量
              const uniqueNodes = new Set();
              relations.forEach((relation) => {
                const [source, target] = relation.split(",");
                if (source) uniqueNodes.add(source);
                if (target) uniqueNodes.add(target);
              });
              const nodeCount = uniqueNodes.size;

              // 完成当前任务
              if (task1 && task1.steps && task1.steps.length > 0) {
                task1.showStepChecks = true;
                task1.completed = true;
                task1.isCompleted = true;
                task1.isActive = false;
                if (!task1.userCollapsed) {
                  task1.collapsed = true;
                }
              }

              // 创建新的思维导图任务
              const mindmapTask = {
                title: `任务五：生成"${this.currentQuery}"产业链图谱`,
                steps: [
                  {
                    type: "mindmap",
                    data: {
                      relations: relations,
                      nodes: nodes,
                      industry_name: this.currentQuery || "",
                    },
                  },
                ],
                collapsed: false,
                isTypingStep: false,
                isCompleted: true,
                completed: true,
                isActive: true,
                completedSteps: {},
                showStepChecks: true,
              };

              // 添加新的思维导图任务
              const lastAssistantMessage = this.messages
                .filter((m) => m.role === "assistant")
                .pop();
              if (lastAssistantMessage) {
                if (!lastAssistantMessage.tasks) {
                  this.$set(lastAssistantMessage, "tasks", []);
                }
                lastAssistantMessage.tasks.push(mindmapTask);
              }

              setTimeout(() => {
                this.messages.push({
                  role: "assistant",
                  tasks: [
                    {
                      title: `本次任务总计耗时：${timeString}，共检索${this.globalArticleCount}篇文章，生成节点数量：${nodeCount}个`,
                      customClass: "task-summary",
                    },
                  ],
                });
                // 恢复发送按钮状态
                this.isTypingq = false;
                this.inputMessage = "";
              }, 10000);
              this.$nextTick(() => {
                this.scrollToBottom();
              });
            }
          }
          resolve();
        } else if (json.type === "5") {
          // 如果上一次处理的不是 type 5，说明这是新一轮的 type 5 消息，需要清空之前的数据
          if (this.currentType !== "5") {
            this.collectedArticles = [];
            // 生成新的组ID
            this.currentGroupId = Date.now();
            // 不重置全局计数器
          }
          // 更新当前消息类型
          this.currentType = "5";

          const urlMatch = json.data.match(/(.+?)url:(.+)/i);
          if (urlMatch) {
            const title = urlMatch[1].trim();
            const url = urlMatch[2].trim();

            // 将文章添加到收集数组中，并确保不重复
            const isDuplicate = this.collectedArticles.some(
              (article) => article.url === url || article.title === title
            );

            if (!isDuplicate) {
              this.globalArticleCount++; // 增加全局计数
              // 打印当前新增的文章信息
              // console.log("新增文章:", {
              //   title: title,
              //   url: url,
              //   当前批次序号: this.collectedArticles.length + 1, // 当前批次的序号
              //   全局序号: this.globalArticleCount, // 全局序号
              // });

              this.collectedArticles.push({
                title: title,
                url: url,
                summary: "",
                source: "行业报告",
                date: new Date().toLocaleDateString(),
                type: "industry",
                groupId: this.currentGroupId, // 添加组标识符
              });
            }

            const relatedContent = {
              topic: {
                title: this.currentQuery || "产业链分析",
                type: "industry",
                articleCount: this.collectedArticles.length,
                analysisCount: 0,
                totalArticleCount: this.globalArticleCount, // 添加全局文章计数
                extractedNodeTitle: this.extractedNodeTitle,
              },
              articles: [...this.collectedArticles],
              groupId: this.currentGroupId, // 添加组标识符
            };

            // 更新侧边栏
            this.$root.$emit("update-sidebar", relatedContent);

            if (task1 && task1.steps) {
              task1.steps.push({
                isLink: true,
                title: title,
                url: url,
              });

              this.$nextTick(() => {
                this.scrollToBottom();
                resolve();
              });
            } else {
              resolve();
            }
          } else {
            resolve();
          }
        } else {
          resolve();
        }
      });
    },
    createSSE(v) {
      // 重置进度相关变量
      this.taskProgress = 0;
      this.taskCount = 0;
      this.firstTaskStartTime = Date.now();
      
      // 发送初始状态
      this.$root.$emit('update-progress', {
        progress: 0,
        taskName: v,
        status: '准备中',
        totalArticles: 0,
        timeElapsed: 0
      });

      // this.isInitialLoad = false;

      // 收起侧边栏并更新数据
      this.$root.$emit("message-processing");
      // this.$root.$emit("update-chain-status");

      this.pendingRequests.add(v);
      this.currentQuery = v;

      // 重置第一次任务开始时间
      this.firstTaskStartTime = null;

      this.articleUrlSet = new Set();
      this.accumulatedArticles = [];

      this.localRelatedContent = {
        topic: {
          title: v || "产业链分析",
          type: "industry",
          articleCount: 0,
          analysisCount: 0,
        },
        articles: [],
      };

      const that = this;
      const controller = new AbortController();
      const signal = controller.signal;
      const url = `${process.env.VUE_APP_API_SERVER}/api/industrial/process_stream`;
      const accessToken = localStorage.getItem("access_token");
      const tokenType = localStorage.getItem("token_type");

      if (!accessToken || !tokenType) {
        console.error("Token不存在，请先登录");
        // 清除登录状态
        localStorage.removeItem("isLoggedIn");
        localStorage.removeItem("access_token");
        localStorage.removeItem("token_type");
        this.pendingRequests.delete(v);

        // 先显示消息提示
        this.$message({
          message: "请先登录",
          type: "error",
          duration: 2000,
          onClose: () => {
            // 消息关闭后再跳转
            this.$router.push("/login");
          },
        });
        return;
      }

      let isConnectionClosed = false;
      let hasError = false;

      const startFetchEventSource = () => {
        if (isConnectionClosed || hasError) {
          return;
        }

        // const _url = url
        // const _url = "http://127.0.0.1:3333/sse/ssss";
        fetchEventSource(url, {
          method: "POST",
          signal: signal,
          headers: {
            Authorization: `${tokenType} ${accessToken}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            industry_name: v,
            custom_urls: this.successful_files
              .map((file) => file.response?.fileurl)
              .filter(Boolean),
            sites: this.searchSites.map((site) => site.url), // 只传递域名部分
          }),
          openWhenHidden: true,
          onopen(response) {
            if (response.ok && response.status === 200) {
              // console.log('Connection opened for query:', v);
              console.log("------- concent --------- ");
            } else if (response.status === 401) {
              console.error("Token已失效，请重新登录");
              that.$message.error("登录已过期，请重新登录");
              localStorage.removeItem("access_token");
              localStorage.removeItem("token_type");
              that.$router.push("/login");
            } else {
              console.error(`连接状态异常: ${response.status}`);
            }
          },
          onmessage(msg) {
            // console.log('msg', msg);
            if (!msg || !msg.data) return;

            // 更新侧边栏数据
            // that.$root.$emit("update-chain-status");

            let json = {};
            const messageData = msg.data;
            // console.log('messageData', messageData);
            try {
              const lines = messageData
                .split("\n")
                .filter((line) => line.trim());
              lines.forEach((line) => {
                line = line.trim();
                if (line.includes("type:")) {
                  json.type = line.split("type:")[1].trim();
                } else if (line.startsWith("data:")) {
                  let content = line.substring(5).trim();
                  if (content.startsWith("data:")) {
                    content = content.substring(5).trim();
                  }
                  json.data = (json.data ? json.data + "\n" : "") + content;
                } else if (line.trim().length > 0) {
                  json.data = (json.data ? json.data + "\n" : "") + line;
                }
              });

              if (json.data) {
                // 检查是否是ping消息
                if (json.data.startsWith("ping")) {
                  // 更新当前消息的内容为加载状态
                  const currentMessage =
                    that.messages[that.messages.length - 1];
                  if (currentMessage && currentMessage.role === "assistant") {
                    currentMessage.content = "正在思考...";
                    that.$nextTick(() => {
                      that.scrollToBottom();
                    });
                  }
                  return;
                }

                json.data = json.data
                  .replace(/#{1,6}\s+/g, "")
                  .replace(/\*\*(.*?)\*\*/g, "$1")
                  .replace(/###|####/g, "")
                  .replace(/^\s*[-—]\s*/gm, "")  // 修改为多行模式
                  .replace(/^\s*\d+\.\s*/gm, "")  // 修改为多行模式
                  .replace(/^data[:：]\s*/gm, "")  // 修改为多行模式
                  .trim();
              }

              // 检查是否是处理结束的信号
              if (
                json.data &&
                (json.data.includes("处理结束") ||
                  json.data.includes("分析结束") ||
                  json.data.includes("总结完毕"))
              ) {
                // console.log('处理完成，准备更新侧边栏');

                // 清理定时器
                if (that.loadingCheckInterval) {
                  clearInterval(that.loadingCheckInterval);
                  that.loadingCheckInterval = null;
                }

                // 请求结束时，一次性更新侧边栏
                // that.updateSidebarWithAccumulatedArticles();

                that.pendingRequests.delete(v);
                return;
              }

              if (Object.keys(json).length > 0) {
                that.messageQueue.push(json);
                if (!that.isProcessingMessage) {
                  that.processMessageQueue();
                }
              }
            } catch (error) {
              console.error("处理消息时出错:", error);
              // 只记录错误，不中断连接
            }
          },
          onerror(err) {
            console.error("EventSource error:", err);
            // 只记录错误，不中断连接
          },
          onclose() {
            // 连接关闭时更新数据
            // that.$root.$emit("update-chain-status");
            // 清理定时器
            if (that.loadingCheckInterval) {
              clearInterval(that.loadingCheckInterval);
              that.loadingCheckInterval = null;
            }

            // 确保在连接关闭时更新侧边栏
            // that.updateSidebarWithAccumulatedArticles();

            that.pendingRequests.delete(v);
            // 重置状态，确保可以发送新消息
            that.isWaitingForResponse = false;
            that.isTyping = false;
            that.isTypingq = false;
          },
        });
      };

      startFetchEventSource();

      // 简化清理逻辑
      controller.signal.addEventListener("abort", () => {
        this.pendingRequests.delete(v);
      });
    },
    async sendMessage() {
      const query = this.inputMessage.trim();
      if (!query) return;
      if (!this.isTyping && !this.isWaitingForResponse) {
        // 设置状态
        this.isWaitingForResponse = true;
        this.isTyping = true;
        this.isReceiving = false;
        this.textToType = "";
        this.showWelcomeMessage = false;
        
        // 进行产业链名称验证（验证成功时会在validateIndustryName中调用addNewChainToSidebar）
        const isValid = await this.validateIndustryName(query);
        
        // 清空输入
        this.inputMessage = "";
        this.showSuggestions = false;

        // 只有在验证成功时才添加用户消息
        if (isValid) {
          // 创建用户消息对象
          const userMessage = {
            id: Date.now().toString(),
            role: "user",
            content: query,
            attachments: [...this.successful_files], // 深拷贝附件列表
          };

          // 添加到消息列表
          this.messages.push(userMessage);
          this.successful_files = [];

          this.scrollToBottom();
        } else {
          // 重置等待状态
          this.isWaitingForResponse = false;
          this.isTyping = false;
        }
      }
    },
    async cancelProcess() {
      // 停止所有打字效果
      this.isTypingq = false;
      this.isTyping = false;
      
      // 清空消息队列并停止消息处理
      this.messageQueue = [];
      this.isProcessingMessage = false;
      
      // 如果有活动任务，停止其打字效果
      if (task1 && task1.steps) {
        task1.isTypingStep = false;
        task1.isCompleted = true;
        task1.completed = true;
      }

      // 停止所有消息的打字效果
      this.messages.forEach(message => {
        if (message.isTyping) {
          message.isTyping = false;
        }
      });

      // 清空pendingRequests，确保可以发送新消息
      if (this.currentQuery) {
        this.pendingRequests.delete(this.currentQuery);
      }
      this.isWaitingForResponse = false;

      // 调用取消API
      if (this.inputMessage) {
        api.user
          .cancelprocess({
            industry_name: this.inputMessage,
          })
          .then((res) => {
            console.log(res);
            this.qxmessage = res.message;
            console.log(this.qxmessage, "sds");

            this.messages.push({
              role: "assistant",
              tasks: [
                {
                  title: this.qxmessage,
                },
              ],
            });

            this.currentProcessingQuery = null;
          });
      }
    },

    extractIndustryName(message) {
      const matches = message.match(/[「『"']([^「『"']+)[」』"']产业/);
      if (matches && matches[1]) {
        return matches[1];
      }

      const words = message.split(/\s+/);
      for (const word of words) {
        if (
          word.length >= 2 &&
          !word.includes("产业链") &&
          !word.includes("分析")
        ) {
          return word;
        }
      }

      return "新能源";
    },

  async  typeTaskStep(task, content, callback, messageType) {
     console.log("typeTaskStep", task);
      // 添加messageType参数
      if (!task) return;
      console.log("add steps", task);
      if (!task.completedSteps) {
        this.$set(task, "completedSteps", {});
      }
      if (!task.showStepChecks) {
        task.showStepChecks = false;
      }
      const stepIndex = task.steps ? task.steps.length : 0;

      if (!task.steps) {
        this.$set(task, "steps", []);
      }

      const urlMatch = content.match(/(.+?)url:(.+)/i);

      if (urlMatch) {
        task.steps.push({
          isLink: true,
          title: urlMatch[1].trim(),
          url: urlMatch[2].trim(),
        });
        setTimeout(() => {
          if (callback) {
            this.$nextTick(() => {
              callback();
            });
          }
        }, 3000);
      } else {

        task.steps.push({
          content: content,
          type: messageType, // 使用传入的messageType
        });
        task.isTypingStep = true;
        task.isActive = true;

        if (stepIndex === 0) {
          task.isCompleted = false;
          task.completed = false;
          task.collapsed = false;
        }

        this.scrollToBottom();
        // 添加新的task-steps后添加滚动监听
        this.addScrollListenerToTaskSteps();

        // 减少延迟时间，使用固定的较短延迟
        if (callback) {
          setTimeout(() => {
            callback();
          }, Math.min(content.length * 10, 500)); // 最多等待500ms
        }
      }
    },

    onTaskStepComplete(task, stepIndex) {
      console.log("onTaskStepComplete", task, stepIndex);
      if (!task || !task.steps) return;

      if (stepIndex === task.steps.length - 1) {
        task.isTypingStep = false;
      }

      if (!task.completedSteps) {
        this.$set(task, "completedSteps", {});
      }

      // 设置当前步骤为已完成
      this.$set(task.completedSteps, stepIndex, true);

      // 显示步骤的对勾图标
      task.showStepChecks = true;

      this.$nextTick(() => {
        this.processNextStep(task);
      });
    },

    processNextStep(task) {
      if (!task || !task.steps) return;

      const currentStepIndex = Object.keys(task.completedSteps).length;
      if (currentStepIndex < task.steps.length) {
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      } else {
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      }
    },

    startTypingEffect(messageIndex) {
      this.isTyping = true;
      const message = this.messages[messageIndex];
      const fullContent = message.fullContent;
      let currentIndex = 0;

      const typingInterval = setInterval(() => {
        if (currentIndex < fullContent.length) {
          this.messages[messageIndex].content = fullContent.substring(
            0,
            currentIndex + 1
          );
          currentIndex++;

          this.scrollToBottom();
        } else {
          clearInterval(typingInterval);
          this.messages[messageIndex].isTyping = false;
          this.isTyping = false;
        }
      }, this.typingSpeed);
    },

    scrollToBottom() {
      this.$nextTick(() => {
        // 主消息容器滚动
        const container = this.$refs.messagesContainer;
        if (container) {
          const scrollOptions = {
            top: container.scrollHeight,
            behavior: "smooth",
          };

          const isLargeScroll =
            container.scrollHeight - container.scrollTop >
            container.clientHeight * 2;
          if (isLargeScroll) {
            scrollOptions.behavior = "auto";
          }

          container.scrollTo(scrollOptions);
        }
        
        // 为每个任务步骤容器设置滚动
        const taskStepsContainers = document.querySelectorAll('.task-steps');
        taskStepsContainers.forEach(container => {
          if (container && !this.userIsScrolling) {
            // 只有当用户不是手动滚动时才自动滚动
            container.scrollTo({
              top: container.scrollHeight,
              behavior: "smooth"
            });
          }
        });
      });
    },

    showAddEditDialog() {
      this.isEditing = false;
      this.siteForm.name = "";
      this.siteForm.url = "";
      this.addEditDialogVisible = true;
    },

    editSite(index) {
      this.isEditing = true;
      this.editingIndex = index;
      this.siteForm.name = this.searchSites[index].name;
      this.siteForm.url = this.searchSites[index].url;
      this.addEditDialogVisible = true;
    },

    confirmAddEditSite() {
      if (this.isEditing) {
        if (this.editingIndex !== -1) {
          // 确保只保存域名部分，移除可能的协议和路径
          const url = this.siteForm.url
            .replace(/^(https?:\/\/)?(www\.)?/i, "")
            .split("/")[0];
          this.searchSites[this.editingIndex].name = this.siteForm.name;
          this.searchSites[this.editingIndex].url = url;
          this.editingIndex = -1;
        }
      } else {
        if (this.siteForm.name && this.siteForm.url) {
          // 确保只保存域名部分，移除可能的协议和路径
          const url = this.siteForm.url
            .replace(/^(https?:\/\/)?(www\.)?/i, "")
            .split("/")[0];
          this.searchSites.push({ name: this.siteForm.name, url: url });
        }
      }
      this.addEditDialogVisible = false;

      // 确保数据状态更新后，如果有活动查询，则更新请求
      if (this.currentQuery && !this.pendingRequests.has(this.currentQuery)) {
        this.$nextTick(() => {
          this.createSSE(this.currentQuery);
        });
      }
    },

    deleteSite(index) {
      this.searchSites.splice(index, 1);

      // 确保数据状态更新后，如果有活动查询，则更新请求
      if (this.currentQuery && !this.pendingRequests.has(this.currentQuery)) {
        this.$nextTick(() => {
          this.createSSE(this.currentQuery);
        });
      }
    },
    handleClickOutside(event) {
      const inputBox = this.$refs.inputBox;
      const inputField = this.$refs.inputField;
      if (inputBox && !inputBox.contains(event.target)) {
        inputField.focus();
      }
    },
    handlePreview() {
      // 文件预览方法
    },
    handleRemove(file, successful_files) {
      // 从 successful_files 数组中找到并删除对应文件
      const index = this.successful_files.findIndex(f => f.name === file.name);
      if (index !== -1) {
        this.successful_files.splice(index, 1);
      }
    },
    handleExceed(files, successful_files) {
      this.$message.warning(
        `当前限制选择 5 个文件，本次选择了 ${files.length} 个文件，共选择了 ${
          files.length + successful_files.length
        } 个文件`
      );
    },
    toggleTask(task) {
      if (task.isCompleted || task.isActive) {
        task.collapsed = !task.collapsed;
        task.userCollapsed = !task.collapsed;
      }
    },
    onTypingComplete(message) {
      message.isTyping = false;
      this.isTyping = false;
    },
    async quickAction(action) {
      this.isInitialLoad = false;

      if (!action || action.trim() === "") {
        this.$message.warning("快捷操作内容不能为空");
        return;
      }

      if (this.isProcessingMessage || this.pendingRequests.size > 0) {
        this.$message.warning("请等待当前请求处理完成");
        return;
      }

      // 进行产业链名称验证
      await this.validateIndustryName(action);
    },
    async handleAIResponse(message) {
      const relatedContent = await this.generateRelatedContent(message);

      this.$root.$emit("update-sidebar", relatedContent);
    },
    async generateRelatedContent(message) {
      const topic = {
        title: "机器人产业链分析",
        type: "industry",
        articleCount: 12,
        analysisCount: 3,
      };

      const articles = [
        {
          type: "深度分析",
          date: "2024-03-15",
          title: "2024年机器人行业市场规模及发展前景分析",
          summary: "随着人工智能技术的快速发展，机器人产业迎来新的发展机遇...",
          source: "前瞻产业研究院",
          url: "https://example.com/article1",
        },
      ];

      const marketData = [
        {
          title: "市场规模",
          value: "2,358亿元",
          changeRate: "+15.6%",
          trend: "up",
          icon: "el-icon-money",
        },
      ];

      const companies = [
        {
          name: "科大讯飞",
          type: "人工智能",
          logo: "https://example.com/logo1.png",
          stockCode: "SZ002230",
          price: "48.25",
          priceChange: 2.35,
        },
      ];

      return {
        topic,
        articles,
        marketData,
        companies,
      };
    },
    focusInput() {
      this.$refs.inputField.focus();
    },
    beforeUpload(file) {
      // 文件类型限制
      const allowedTypes = [
        "image/jpeg",
        "image/png",
        "application/pdf",
        "application/msword",
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      ];
      const isValidType = allowedTypes.includes(file.type);

      // 文件大小限制（10MB）
      const isLt10M = file.size / 1024 / 1024 < 30;

      if (!isValidType) {
        this.$message.error("只能上传 JPG/PNG/PDF/DOC/DOCX 格式的文件!");
        return false;
      }

      if (!isLt10M) {
        this.$message.error("文件大小不能超过 30MB!");
        return false;
      }

      return true;
    },

    handleFileChange(file, successful_files) {
      // 当文件状态改变时（添加/删除），这个方法会被调用
      if (successful_files.length > 0) {
        // 检查是否所有文件都符合要求
        const invalidFiles = successful_files.filter((f) => !this.validateFile(f.raw));
        if (invalidFiles.length > 0) {
          this.$message.error("存在不符合要求的文件，请检查后重试");
          // 从文件列表中移除不符合要求的文件
          invalidFiles.forEach((invalidFile) => {
            const index = successful_files.indexOf(invalidFile);
            if (index > -1) {
              successful_files.splice(index, 1);
            }
          });
          return;
        }

        // 创建 FormData
        const formData = new FormData();
        successful_files.forEach((f) => {
          formData.append("files", f.raw);
        });
        formData.append("folder", "general");

        // 发起上传请求
        fetch(this.uploadUrl, {
          method: "POST",
          headers: {
            Authorization: this.uploadHeaders.Authorization,
          },
          body: formData,
        })
          .then((response) => {
            if (!response.ok) {
              throw new Error("上传失败");
            }
            return response.json();
          })
          .then((result) => {
            if (result.successful_files && result.successful_files.length > 0) {
              result.successful_files.forEach((fileInfo) => {
                const targetFile = successful_files.find(
                  (f) => f.name === fileInfo.file_name
                );
                if (targetFile) {
                  targetFile.response = {
                    fileurl: fileInfo.file_name,
                  };
                }
              });
              this.successful_files = [...successful_files]; // 使用展开运算符创建新数组
              this.$message.success(result.message || "所有文件上传成功");
            }
          })
          .catch((error) => {
            console.error("上传错误:", error);
            this.$message.error("文件上传失败");
            // 发生错误时清空文件列表
            this.successful_files = [];
          });
      }
    },

    validateFile(file) {
      // 文件类型限制
      const allowedTypes = [
        "image/jpeg",
        "image/png",
        "application/pdf",
        "application/msword",
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      ];
      const isValidType = allowedTypes.includes(file.type);

      // 文件大小限制（10MB）
      const isLt10M = file.size / 1024 / 1024 < 30;

      return isValidType && isLt10M;
    },
    async customUpload({ file }) {
      // 这里不需要做任何事情，因为我们会在submitUpload中统一处理
      return false;
    },
    // 新增方法：直接接收思维导图数据并显示
    receiveMindViewData(data) {
      if (!data) return;

      // 添加防抖处理，防止短时间内多次调用
      if (this._mindViewDebounceTimer) {
        clearTimeout(this._mindViewDebounceTimer);
      }

      this._mindViewDebounceTimer = setTimeout(() => {
        // 数据指纹，用于去重
        const dataFingerprint = JSON.stringify(data);

        // 检查是否已经显示了完全相同的数据
        if (this._lastMindViewDataFingerprint === dataFingerprint) {
          return;
        }

        // 保存数据指纹用于去重
        this._lastMindViewDataFingerprint = dataFingerprint;

        // 确保数据包含relations，如果没有则创建空数组
        if (!data.relations) {
          data.relations = [];
        }

        // 确保数据包含nodes，如果没有则创建空数组
        if (!data.nodes) {
          data.nodes = [];
        }

        // 确保有行业名称
        if (!data.industry_name) {
          data.industry_name = "";
        }

        // 创建一个新的思维导图任务
        const mindmapTask = {
          title: `"${
            data.industry_name || data.nodes[0] || "产业链"
          }"产业链图谱`,
          steps: [
            {
              type: "mindmap",
              data: data,
            },
          ],
          collapsed: false,
          isTypingStep: false,
          isCompleted: true,
          completed: true,
          isActive: true,
          completedSteps: {},
          showStepChecks: true,
        };

        // 清空现有消息
        this.messages = [];

        // 创建新的消息来容纳思维导图任务
        this.messages.push({
          role: "assistant",
          content: "",
          isTyping: false,
          tasks: [mindmapTask],
        });

        this.showWelcomeMessage = false;

        // 滚动到底部确保新的思维导图可见
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      }, 300); // 300ms的防抖时间
    },
    // 处理思维导图数据并显示，为了兼容性保留此方法
    handleMindViewData(data) {
      // 直接调用新的方法
      this.receiveMindViewData(data);
    },
    // 添加测试方法
    testMindMap() {
      // 测试数据
      const testRelations = [
        "上游-2,OpenAI-1,part-of",
        "中游-3,OpenAI-1,part-of",
        "下游-4,OpenAI-1,part-of",
        "算力基础设施-5,上游-2,part-of",
        "GPU芯片-6,算力基础设施-5,part-of",
        "云计算平台-7,算力基础设施-5,part-of",
        "专用计算芯片-8,算力基础设施-5,part-of",
        "数据资源-9,上游-2,part-of",
        "训练数据集-10,数据资源-9,part-of",
        "数据标注服务-11,数据资源-9,part-of",
        "基础软件-12,上游-2,part-of",
        "深度学习框架-13,基础软件-12,part-of",
        "分布式训练系统-14,基础软件-12,part-of",
        "数据处理工具链-15,基础软件-12,part-of",
        "大模型研发-16,中游-3,part-of",
        "模型架构设计-17,大模型研发-16,part-of",
        "预训练模型开发-18,大模型研发-16,part-of",
        "模型优化技术-19,大模型研发-16,part-of",
        "训练平台-20,中游-3,part-of",
        "应用接口层-21,下游-4,part-of",
        "API服务-22,应用接口层-21,part-of",
        "模型即服务平台-23,应用接口层-21,part-of",
        "垂直领域应用-24,下游-4,part-of",
        "代码生成-25,垂直领域应用-24,part-of",
        "图像生成-26,垂直领域应用-24,part-of",
        "智能对话系统-27,垂直领域应用-24,part-of",
        "文档处理-28,垂直领域应用-24,part-of",
        "部署支持-29,下游-4,part-of",
        "模型部署工具链-30,部署支持-29,part-of",
        "边缘计算适配-31,部署支持-29,part-of",
        "多模态集成方案-32,部署支持-29,part-of",
      ];
      // 添加测试nodes数据
      const testNodes = [
        "OpenAI",
        "上游",
        "中游",
        "下游",
        "算力基础设施",
        "GPU芯片",
        "云计算平台",
        "专用计算芯片",
        "数据资源",
        "训练数据集",
        "数据标注服务",
        "基础软件",
        "深度学习框架",
        "分布式训练系统",
        "数据处理工具链",
        "大模型研发",
        "模型架构设计",
        "预训练模型开发",
        "模型优化技术",
        "训练平台",
        "应用接口层",
        "API服务",
        "模型即服务平台",
        "垂直领域应用",
        "代码生成",
        "图像生成",
        "智能对话系统",
        "文档处理",
        "部署支持",
        "模型部署工具链",
        "边缘计算适配",
        "多模态集成方案",
      ];
      // 创建一个思维导图数据对象
      const mindmapData = {
        relations: testRelations,
        nodes: testNodes,
        industry_name: "OpenAI",
      };

      // 创建一个新的思维导图任务
      const randomSuffix = Math.floor(Math.random() * 1000);
      const mindmapTask = {
        title: `测试产业链关系图 #${randomSuffix}`,
        steps: [
          {
            type: "mindmap",
            data: mindmapData,
          },
        ],
        collapsed: false,
        isTypingStep: false,
        isCompleted: true,
        completed: true,
        isActive: true,
        completedSteps: {},
        showStepChecks: true,
      };

      // 确保有一个消息来容纳任务
      if (!this.messages.length) {
        this.messages.push({
          role: "assistant",
          content: "",
          isTyping: false,
          tasks: [],
        });
      }

      // 确保第一条消息有tasks数组
      if (!this.messages[0].tasks) {
        this.$set(this.messages[0], "tasks", []);
      }

      // 直接添加新任务到第一条消息的任务列表中
      this.messages[0].tasks.push(mindmapTask);
      this.showWelcomeMessage = false;

      // 滚动到底部确保新的思维导图可见
      this.$nextTick(() => {
        this.scrollToBottom();
      });
    },
    // 更新侧边栏，一次性处理所有累积的文章
    updateSidebarWithAccumulatedArticles() {
      // console.log('开始更新侧边栏，累积文章数量:', this.accumulatedArticles ? this.accumulatedArticles.length : 0);

      // 确保数组存在
      if (!this.accumulatedArticles) {
        this.accumulatedArticles = [];
      }

      // 如果没有累积的文章，不需要更新
      if (this.accumulatedArticles.length === 0) {
        // console.log('没有累积的文章，跳过侧边栏更新');
        return;
      }

      // 使用严格去重逻辑处理文章列表
      const uniqueArticles = this.removeDuplicates(this.accumulatedArticles);
      // console.log(`文章去重: ${this.accumulatedArticles.length} -> ${uniqueArticles.length}`);

      // 确保本地相关内容对象存在
      if (!this.localRelatedContent) {
        this.localRelatedContent = {
          topic: {
            title: this.currentQuery || "产业链分析",
            type: "industry",
            articleCount: 0,
            analysisCount: 0,
          },
          articles: [],
        };
      }

      // 设置新的本地相关内容
      this.localRelatedContent = {
        topic: {
          title: this.currentQuery || "产业链分析",
          type: "industry",
          articleCount: uniqueArticles.length,
          analysisCount: 0,
        },
        articles: uniqueArticles.map((article) => {
          // 确保每篇文章都有所有必要的字段
          return {
            title: article.title || "未知标题",
            url: article.url || "#",
            summary: article.summary || "",
            // 添加默认值确保格式一致性
            source: article.source || "行业报告",
            date: article.date || new Date().toLocaleDateString(),
            type: article.type || "industry",
          };
        }),
      };

      // 发送更新事件给侧边栏
      // console.log('发送侧边栏更新事件，文章数量:', uniqueArticles.length);
      this.$root.$emit("update-sidebar", this.localRelatedContent);

      // 清空文章收集数组和URL集合，确保下次请求时重新开始
      this.accumulatedArticles = [];
      this.articleUrlSet.clear();

      // console.log('侧边栏更新完成，累积文章已重置');
    },

    // 辅助方法：移除重复文章
    removeDuplicates(articles) {
      if (!articles || !Array.isArray(articles)) {
        console.warn("removeDuplicates收到无效的文章数组");
        return [];
      }

      const uniqueArticles = [];
      const urlSet = new Set();
      const titleSet = new Set();

      articles.forEach((article) => {
        // 如果文章对象无效，跳过
        if (!article || typeof article !== "object") {
          console.warn("跳过无效文章对象");
          return;
        }

        // 获取标题和URL，提供默认值以防字段缺失
        const title = article.title || "";
        const url = article.url || "";

        // 如果标题或URL为空，跳过
        if (!title || !url) {
          console.warn("跳过缺少标题或URL的文章");
          return;
        }

        // 创建唯一键进行去重判断
        const key = `${title}|${url}`;

        // 如果URL或标题已存在，则跳过
        if (urlSet.has(url) || titleSet.has(title)) {
          // console.log(`跳过重复文章: ${title}`);
          return;
        }

        // 添加到去重集合中
        urlSet.add(url);
        titleSet.add(title);

        // 添加到结果数组
        uniqueArticles.push(article);
      });

      // console.log(`文章去重完成，结果数量: ${uniqueArticles.length}`);
      return uniqueArticles;
    },
    // 添加取消发送方法
    cancelSend() {
      // 关闭确认对话框
      this.showConfirmDialog = false;
      
      // 重置状态
      this.isInitialLoad = true;
      this.showWelcomeMessage = true;
      this.isWaitingForResponse = false;
      this.isTyping = false;
      this.isTypingq = false;
      this.pendingsend = false;
      
      // 保留输入内容
      this.inputMessage = this.pendingSendMessage;
      
      // 添加延迟确保UI状态更新
      this.$nextTick(() => {
        console.log('取消发送，重置状态：', {
          isInitialLoad: this.isInitialLoad,
          showWelcomeMessage: this.showWelcomeMessage
        });
        // 强制更新视图
        this.$forceUpdate();
        
        // 清空消息数组以确保欢迎消息显示
        if (this.isInitialLoad && this.showWelcomeMessage) {
          this.messages = [];
        }
      });
    },

    // 添加确认发送方法
    confirmSend() {
      const message = this.pendingSendMessage;
      this.inputMessage = message;
      console.log(this.inputMessage, "确认发送的消息");
      
      // 重置状态
      this.isInitialLoad = false;
      this.showWelcomeMessage = false;
      this.showConfirmDialog = false;
      this.isTypingq = true;
      this.pendingsend = false;
      this.isWaitingForResponse = true;
      this.isTyping = true;

      // 收起侧边栏并更新数据
      this.$root.$emit("message-processing");
      // this.$root.$emit("update-chain-status");

      // 添加用户消息
      // this.messages.push({
      //   role: "user",
      //   content: this.inputMessage,
      //   tasks: []
      // });

      // 添加助手消息
      // this.messages.push({
      //   role: "assistant",
      //   content: "",
      //   isTyping: true,
      //   tasks: []
      // });

      // 滚动到底部并创建SSE连接
      this.$nextTick(() => {
        console.log('确认发送，重置状态：', {
          isInitialLoad: this.isInitialLoad,
          showWelcomeMessage: this.showWelcomeMessage
        });
        this.scrollToBottom();
        this.createSSE(message);
      });
    },
    // 添加获取进度状态的辅助方法
    getProgressStatus(progress) {
      if (progress === 0) return '已取消';
      if (progress === 100) return '已完成';
      if (progress > 0) return '处理中';
      return '准备中';
    },
    // 添加任务步骤容器的滚动事件处理函数
    handleTaskStepsScroll(event) {
      const container = event.target;
      
      // 当用户向上滚动时，设置状态为手动滚动
      if (container.scrollTop < this.lastScrollTop) {
        this.userIsScrolling = true;
        
        // 清除之前的定时器
        if (this.scrollTimeoutId) {
          clearTimeout(this.scrollTimeoutId);
        }
        
        // 设置一个定时器，5秒后重置滚动状态
        this.scrollTimeoutId = setTimeout(() => {
          this.userIsScrolling = false;
        }, 5000);
      }
      
      // 当用户滚动到底部时，重置滚动状态
      const isAtBottom = container.scrollHeight - container.scrollTop <= container.clientHeight + 10;
      if (isAtBottom) {
        this.userIsScrolling = false;
      }
      
      // 更新上次滚动位置
      this.lastScrollTop = container.scrollTop;
    },
    
    // 添加一个方法来在新添加task-steps时添加事件监听
    addScrollListenerToTaskSteps() {
      this.$nextTick(() => {
        const taskStepsContainers = document.querySelectorAll('.task-steps');
        taskStepsContainers.forEach(container => {
          if (container) {
            // 移除已有的监听器，避免重复添加
            container.removeEventListener('scroll', this.handleTaskStepsScroll);
            // 添加新的监听器
            container.addEventListener('scroll', this.handleTaskStepsScroll);
          }
        });
      });
    },
    // 新增方法：添加新的产业链到侧边栏
    addNewChainToSidebar(message) {
      // 提取可能的产业链名称（这里简化处理，实际中可能需要更复杂的逻辑）
      const industryKeywords = ['产业', '行业', '领域', '产业链', '工业', '制造', '技术'];
      
      // 检查用户消息中是否包含产业相关关键词
      if (industryKeywords.some(keyword => message.includes(keyword))) {
        // 识别可能的产业名称
        let industryName = '';
        
        // 简单的规则匹配，实际应用中可能需要更复杂的NLP处理
        if (message.includes('分析')) {
          const parts = message.split('分析');
          if (parts.length > 0 && parts[0].length > 0) {
            industryName = parts[0].trim();
          }
        } else {
          // 从消息中提取可能的产业名称（简单实现）
          const words = message.split(/[，。！？,.!? ]/);
          for (const word of words) {
            if (word.length > 1 && word.length < 10) {
              industryName = word;
              break;
            }
          }
        }
        
        // 如果提取到了产业名称，则添加到侧边栏
        if (industryName) {
          // 使用事件总线调用侧边栏组件的方法
          this.$root.$emit('add-new-chain-status', industryName);
          console.log(`已添加新的产业链到侧边栏: ${industryName}`);
        }
      } else {
        // 如果没有找到关键词，直接使用输入作为产业链名称
        this.$root.$emit('add-new-chain-status', message);
        console.log(`已添加新的产业链到侧边栏: ${message}`);
      }
    },
  },
};
</script>

<style scoped>
.task-steps *:not(i){
    line-height: 1.6rem;
    letter-spacing: 0.1rem;
}
@import "./styles.css";
.file-list-popover {
  max-height: 300px;
  overflow-y: auto;
}

.no-files {
  color: #909399;
  text-align: center;
  padding: 10px;
}

.file-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.file-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px;
  border-radius: 4px;
  background-color: #f5f7fa;
}

.file-info {
  display: flex;
  align-items: center;
  gap: 8px;
}

.file-name {
  font-size: 14px;
  color: #606266;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.file-actions {
  display: flex;
  align-items: center;
}

.delete-btn {
  padding: 2px 6px;
}

.delete-btn:hover {
  color: #f56c6c;
}

.file-count {
  margin-left: 4px;
  font-size: 12px;
  color: #909399;
}

.mindmap-container {
  width: 100%;
  height: 500px;
  margin: 10px 0;
  border-radius: 8px;
  overflow: hidden;
  background-color: #fff;
}

.loading-indicator {
  margin: 10px 0; /* 修改为上下外边距 */
  width: fit-content;
  background-color: #f5f5f5;
  border-radius: 12px;
  display: flex;
  align-items: center;
  padding: 8px 16px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.loading-dots {
  display: flex;
  gap: 4px; /* 减小点的间距 */
}

.loading-dots span {
  width: 6px; /* 减小点的大小 */
  height: 6px;
  background-color: #1a73e8;
  border-radius: 50%;
  animation: blink 1.4s infinite both;
  opacity: 0.7;
}

.loading-dots span:nth-child(2) {
  animation-delay: 0.2s;
}

.loading-dots span:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes blink {
  0%,
  80%,
  100% {
    transform: scale(0.5);
    opacity: 0.4;
  }
  40% {
    transform: scale(1);
    opacity: 1;
  }
}

.loading-text {
  margin-left: 8px;
  font-size: 13px; /* 减小字体大小 */
  color: #333;
  font-weight: 500;
}

.confirm-dialog {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  padding: 24px;
  z-index: 1000;
  width: 90%;
  max-width: 500px;
  border: 1px solid rgba(0, 0, 0, 0.06);
}

.confirm-content {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.confirm-title {
  font-size: 18px;
  font-weight: 600;
  color: #2c2c36;
  margin-bottom: 4px;
  line-height: 1.4;
}

.confirm-desc {
  font-size: 14px;
  color: #606266;
  line-height: 1.8;
  margin: 8px 0;
  background: #f8f9fa;
  padding: 16px;
  border-radius: 8px;
}

.confirm-buttons {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 8px;
  padding-top: 16px;
  border-top: 1px solid #ebeef5;
}

.confirm-buttons .el-button {
  padding: 10px 24px;
  font-size: 14px;
  border-radius: 6px;
}

.confirm-buttons .el-button--primary {
  background: #409eff;
  border-color: #409eff;
  font-weight: 500;
}

.confirm-buttons .el-button--default {
  border-color: #dcdfe6;
  color: #606266;
}

.confirm-buttons .el-button--default:hover {
  color: #409eff;
  border-color: #c6e2ff;
  background-color: #ecf5ff;
}

.confirm-buttons .el-button--primary:hover {
  background: #66b1ff;
  border-color: #66b1ff;
}

.button-container {
  display: flex;
  align-items: center;
  gap: 10px;
}

.left-buttons {
  display: flex;
  gap: 10px;
}

.task-step {
  position: relative;
  margin: 20px 0;
}

/* 基础消息样式 */
.message-content-type {
  padding: 12px;
  border-radius: 8px;
  white-space: pre-wrap;

  position: relative;
  padding-left: 20px;
  color: #5e6772;
}

/* Type2 样式 */
.type2-content {
  background-color: #f3f5fc;
  color: #5e6772;
  position: relative;
  padding-left: 20px;
}

.type2-content::before {
  content: "";
  position: absolute;
  left: -21px;
  top: 0;
  bottom: 0;
  width: 2px;
  background-color: #ccc;
  border-radius: 2px;
}

/* Type4 样式 */
.type4-content {
  background-color: #f3f5fc;
  color: #5e6772;
  position: relative;
  padding-left: 20px;
}

.type4-content::before {
  content: "";
  position: absolute;
  left: -21px;
  top: 0;
  bottom: 0;
  width: 2px;
  background-color: #ccc;
  border-radius: 2px;
}

/* Type5 样式 */
.type5-content {
  background-color: #f3f5fc;
  color: #276749;
  position: relative;
  padding-left: 20px;
  border-radius: 8px;
}

.type5-content::before {
  content: "";
  position: absolute;
  left: -21px;
  top: 0;
  bottom: 0;
  width: 2px;
  background-color: #ccc;
  border-radius: 2px;
}

/* 状态图标样式 */
.step-status {
  position: absolute;
  left: -29px;
  top: -1%;
  transform: translateY(-50%);
  z-index: 1;
  background: #1a73e8;
  border-radius: 50%;
  padding: 2px;
  color: #fff;
}

/* 移除旧的task-steps连接线样式 */
.task-steps {
  position: relative;
  padding-left: 30px;
}

/* 添加任务标题样式 */
.task-title {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background-color: #f8fafc;
  border-radius: 6px;
  margin-bottom: 12px;
}
.article-link > a {
  color: #1a73e8;
  text-decoration: none;
  cursor: pointer;
  position: relative;
}

.article-link :hover {
  text-decoration: underline;
}

.article-link {
  padding: 12px;
  position: relative;
}

/* .article-link > a {
  color: #1a73e8;
  text-decoration: none;
  cursor: pointer;
}

.article-link a:hover {
  text-decoration: underline;
} */

.task-summary {
 
  border-radius: 8px;
  margin: 0;
}

.task-summary :deep(span) {
  color: black;
  font-weight: 500;
}
</style>
